home *** CD-ROM | disk | FTP | other *** search
/ Hacks & Cracks / Hacks_and_Cracks.iso / manuals / how to crack / htocrkc2.txt < prev    next >
Text File  |  1996-06-24  |  27KB  |  498 lines

  1.                      HOW TO CRACK, by +ORC, A TUTORIAL
  2.  
  3. ---------------------------------------------------------------------------
  4.  
  5.               LESSON C (2) - How to crack, Cracking as an art
  6.  
  7. ---------------------------------------------------------------------------
  8.  
  9.                               [INSTANT ACCESS]
  10.  
  11.                    --------------------------------------
  12.  
  13.       cracking Instant Access (2) - strainer for the +HCU
  14.  
  15. [SEE LESSON C.1 for the first part of this cracking session]
  16.      Here follow the relevant protection routines for the first
  17. (The "Registration") number_code of Instant Access, with my
  18. comments: you have to investigate a little the following code.
  19.      Later, when you'll crack on your own, try to recognize the
  20. many routines that fiddle with input BEFORE the relevant (real
  21. protection) one. In this case, for instance, a routine checks the
  22. correctness of the numbers of your input:
  23.  
  24. This_loop_checks_that_numbers_are_numbers:
  25. 1B0F:2B00 C45E06    LES    BX,[BP+06]  ; set/reset pointer
  26. 1B0F:2B03 03DF      ADD    BX,DI
  27. 1B0F:2B05 268A07    MOV    AL,ES:[BX]  ; get number
  28. 1B0F:2B08 8846FD    MOV    [BP-03],AL  ; store
  29. 1B0F:2B0B 807EFD30  CMP    BYTE PTR [BP-03],30
  30. 1B0F:2B0F 7C06      JL     2B17        ; less than zero?
  31. 1B0F:2B11 807EFD39  CMP    BYTE PTR [BP-03],39
  32. 1B0F:2B15 7E05      JLE    2B1C        ; between 0 & 9?
  33. 1B0F:2B17 B80100    MOV    AX,0001     ; no, set flag=1
  34. 1B0F:2B1A EB02      JMP    2B1E        ; keep flag
  35. 1B0F:2B1C 33C0      XOR    AX,AX       ; flag=0
  36. 1B0F:2B1E 0BC0      OR     AX,AX       ; is it zero?
  37. 1B0F:2B20 7507      JNZ    2B29        ; flag NO jumps away
  38. 1B0F:2B22 8A46FD    MOV    AL,[BP-03]  ; Ok, get number
  39. 1B0F:2B25 8842CC    MOV    [BP+SI-34],AL ; Ok, store number
  40. 1B0F:2B28 46        INC    SI          ; inc storespace
  41. 1B0F:2B29 47        INC    DI          ; inc counter
  42. 1B0F:2B2A C45E06    LES    BX,[BP+06]  ; reset pointer
  43. 1B0F:2B2D 03DF      ADD    BX,DI       ; point next number
  44. 1B0F:2B2F 26803F00  CMP    BYTE PTR ES:[BX],00 ; input end?
  45. 1B0F:2B33 75CB      JNZ    2B00        ; no:loop next num
  46.  
  47.      You now obviously understand that the "real" string is
  48. stored inside memory location [BP+SI-34]... set a memory
  49. breakpoint on this area to get the next block of code that
  50. fiddles with the transformed input. Notice how this routine
  51. "normalizes" the input, strips the "-" off and puts the 10
  52. numbers together:
  53. user input:  1  2  1  2  1  2  1  2  1  2 End
  54.   1E7F:92E2 31 32 31 32 31 32 31 32 31 32 00 45 AF 1F 70 9B
  55.  Stack ptr:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
  56.      Let's now look at the "real" protection routine: the one
  57. that checks these numbers and throw you out if they are not
  58. "sound". Please pay attention to the following block of code:
  59.  
  60. check_if_sum_other_9_numbers_=_remainder_of_the_third_number:
  61. :4B79 8CD0       MOV    AX,SS ; we'll work inside the stack...
  62. :4B7B 90         NOP
  63. :4B7C 45         INC    BP
  64. :4B7D 55         PUSH   BP    ; save real BP
  65. :4B7E 8BEC       MOV    BP,SP ; BP = stackpointer
  66. :4B80 1E         PUSH   DS    ; save real Datasegment
  67. :4B81 8ED8       MOV    DS,AX ; Datasegment = stacksegment
  68. :4B83 83EC04     SUB    SP,+04
  69. :4B86 C45E06     LES    BX,[BP+06] ; BX points input_start
  70. :4B89 268A07     MOV    AL,ES:[BX] ; load first number
  71. :4B8C 98         CBW               ; care only for low
  72. :4B8D C45E06     LES    BX,[BP+06] ; reset pointer
  73. :4B90 50         PUSH   AX         ; save 1st number
  74. :4B91 268A4701   MOV    AL,ES:[BX+01] ; load 2nd number
  75. :4B95 98         CBW               ; only low
  76. :4B96 8BD0       MOV    DX,AX      ; 2nd number in DX
  77. :4B98 58         POP    AX         ; get 1st number
  78. :4B99 03C2       ADD    AX,DX      ; sum with second
  79. :4B9B C45E06     LES    BX,[BP+06] ; reset pointer
  80. :4B9E 50         PUSH   AX         ; save sum
  81. :4B9F 268A4707   MOV    AL,ES:[BX+07] ; load 8th number
  82. :4BA3 98         CBW               ; only low
  83. :4BA4 8BD0       MOV    DX,AX      ; 8th number in DX
  84. :4BA6 58         POP    AX         ; old sum is back
  85. :4BA7 03C2       ADD    AX,DX      ; sum 1+2+8
  86. :4BA9 C45E06     LES    BX,[BP+06] ; reset pointer
  87. :4BAC 50         PUSH   AX         ; save sum
  88. :4BAD 268A4703   MOV    AL,ES:[BX+03] ; load 4rd number
  89. :4BB1 98         CBW               ; only low
  90. :4BB2 8BD0       MOV    DX,AX      ; #4 in DX
  91. :4BB4 58         POP    AX         ; sum is back
  92. :4BB5 03C2       ADD    AX,DX      ; sum 1+2+8+4
  93. :4BB7 C45E06     LES    BX,[BP+06] ; reset pointer
  94. :4BBA 50         PUSH   AX         ; save sum
  95. :4BBB 268A4704   MOV    AL,ES:[BX+04] ; load 5th number
  96. :4BBF 98         CBW               ; only low
  97. :4BC0 8BD0       MOV    DX,AX      ; #5 in DX
  98. :4BC2 58         POP    AX         ; sum is back
  99. :4BC3 03C2       ADD    AX,DX      ; 1+2+8+4+5
  100. :4BC5 C45E06     LES    BX,[BP+06] ; reset pointer
  101. :4BC8 50         PUSH   AX         ; save sum
  102. :4BC9 268A4705   MOV    AL,ES:[BX+05] ; load 6th number
  103. :4BCD 98         CBW               ; only low
  104. :4BCE 8BD0       MOV    DX,AX      ; #6 in DX
  105. :4BD0 58         POP    AX         ; sum is back
  106. :4BD1 03C2       ADD    AX,DX      ; 1+2+8+4+5+6
  107. :4BD3 C45E06     LES    BX,[BP+06] ; reset pointer
  108. :4BD6 50         PUSH   AX         ; save sum
  109. :4BD7 268A4706   MOV    AL,ES:[BX+06] ; load 7th number
  110. :4BDB 98         CBW               ; only low
  111. :4BDC 8BD0       MOV    DX,AX      ; #7 in DX
  112. :4BDE 58         POP    AX         ; sum is back
  113. :4BDF 03C2       ADD    AX,DX      ; 1+2+8+4+5+6+7
  114. :4BE1 C45E06     LES    BX,[BP+06] ; reset pointer
  115. :4BE4 50         PUSH   AX         ; save sum
  116. :4BE5 268A4708   MOV    AL,ES:[BX+08] ; load 9th number
  117. :4BE9 98         CBW               ; only low
  118. :4BEA 8BD0       MOV    DX,AX      ; #9 in DX
  119. :4BEC 58         POP    AX         ; sum is back
  120. :4BED 03C2       ADD    AX,DX      ; 1+2+8+4+5+6+7+9
  121. :4BEF C45E06     LES    BX,[BP+06] ; reset pointer
  122. :4BF2 50         PUSH   AX         ; save sum
  123. :4BF3 268A4709   MOV    AL,ES:[BX+09] ; load 10th #
  124. :4BF7 98         CBW               ; only low
  125. :4BF8 8BD0       MOV    DX,AX      ; #10 in DX
  126. :4BFA 58         POP    AX         ; sum is back
  127. :4BFB 03C2       ADD    AX,DX      ; 1+2+8+4+5+6+7+9+10
  128. :4BFD 0550FE     ADD    AX,FE50    ; clean sum to 0-51
  129. :4C00 BB0A00     MOV    BX,000A    ; BX holds 10
  130. :4C03 99         CWD               ; only AL
  131. :4C04 F7FB       IDIV   BX         ; remainder in DX
  132. :4C06 C45E06     LES    BX,[BP+06] ; reset pointer
  133. :4C09 268A4702   MOV    AL,ES:[BX+02] ; load now # 3
  134. :4C0D 98         CBW               ; only low
  135. :4C0E 05D0FF     ADD    AX,FFD0    ; clean # 3 to 0-9
  136. :4C11 3BD0       CMP    DX,AX  ; remainder = pampered #3?
  137. :4C13 7407       JZ     4C1C       ; yes, go on good guy
  138. :4C15 33D2       XOR    DX,DX  ; no! beggar off! Zero DX
  139. :4C17 33C0       XOR    AX,AX  ;     and FLAG_AX = FALSE
  140. :4C19 E91701     JMP    4D33       ; go to EXIT
  141. let's_go_on_if_first_check_passed:
  142. :4C1C C45E06     LES    BX,[BP+06] ; reset pointer
  143. :4C1F 268A4701   MOV    AL,ES:[BX+01] ; now load #2 anew
  144. :4C23 98         CBW               ; only low
  145. :4C24 05D7FF     ADD    AX,FFD7    ; pamper adding +3
  146. :4C27 A38D5E     MOV    [5E8D],AX  ; save SEC_+3
  147. :4C2A 3D0900     CMP    AX,0009    ; was it < 9? (no A-F)
  148. :4C2D 7E05       JLE    4C34       ; ok, no 0xletter
  149. :4C2F 832E8D5E0A SUB    WORD PTR [5E8D],+0A ; 0-5 if A-F
  150. :4C34 C45E06     LES    BX,[BP+06] ; reset pointer
  151. :4C37 268A07     MOV    AL,ES:[BX] ; load 1st input number
  152. :4C3A 98         CBW               ; only low
  153. :4C3B 05C9FF     ADD    AX,FFC9    ; pamper adding +7
  154. :4C3E A38F5E     MOV    [5E8F],AX  ; save it in FIR_+7
  155. :4C41 0BC0       OR     AX,AX      ; if #1 > 7
  156. :4C43 7D05       JGE    4C4A       ; no need to add 0xA
  157. :4C45 83068F5E0A ADD    WORD PTR [5E8F],+0A ; FIR_+7 + 0xA
  158. now_we_have_the_sliders_let's_prepare_for_loop:
  159. :4C4A C45E0E     LES    BX,[BP+0E] ; Set pointer to E
  160. :4C4D 26C747020000 MOV  WORD PTR ES:[BX+02],0000 ; 0 flag
  161. :4C53 26C7070000   MOV  WORD PTR ES:[BX],0000    ; 0 flag
  162. :4C58 C706975E0900 MOV  WORD PTR [5E97],0009     ; counter=9
  163. :4C5E E99500     JMP    4CF6       ; Jmp check_counter
  164. loop_8_times:
  165. :4C61 C45E06     LES    BX,[BP+06] ; reset pointer
  166. :4C64 031E975E   ADD    BX,[5E97]  ; add running counter
  167. :4C68 268A07     MOV    AL,ES:[BX] ; load # counter+1
  168. :4C6B 98         CBW               ; only low
  169. :4C6C 50         PUSH   AX         ; save 10th number
  170. :4C6D A18D5E     MOV    AX,[5E8D]  ; ld SEC_+3 down_slider
  171. :4C70 BA0A00     MOV    DX,000A    ; BX holds 0xA
  172. :4C73 F7EA       IMUL   DX         ; SEC_+3 * 0xA
  173. :4C75 03068F5E   ADD    AX,[5E8F]  ; plus FIR_+7 up_slider
  174. :4C79 BAA71E     MOV    DX,1EA7    ; fixed segment
  175. :4C7C 8BD8       MOV    BX,AX ; BX = Lkup_val=(SEC_+3*10+FIR_+7)
  176. :4C7E 8EC2       MOV    ES,DX      ; ES = 1EA7
  177. :4C80 268A870000 MOV    AL,ES:[BX+0000] ; ld 1EA7:[Lkup_val]
  178. :4C85 98         CBW               ; only low: KEY_PAR
  179. :4C86 8BD0       MOV    DX,AX      ; save KEY_PAR in DX
  180. :4C88 58         POP    AX         ; repops 10th number
  181. :4C89 03C2       ADD    AX,DX      ; RE_SULT=KEY_PAR+#10
  182. :4C8B 05D0FF     ADD    AX,FFD0    ; polish RE_SULT
  183. :4C8E 99         CWD               ; only low: RE_SULT
  184. :4C8F 8956FC     MOV    [BP-04],DX ; save here KEY_PAR [9548]
  185. :4C92 8946FA     MOV    [BP-06],AX ; save here RE_SULT [9546]
  186. :4C95 0BD2       OR     DX,DX      ; KEY_PAR < 0?
  187. :4C97 7C0F       JL     4CA8       ; yes: KEY_PAR < 0
  188. :4C99 7F05       JG     4CA0       ; no: KEY_PAR > 0
  189. :4C9B 3D0900     CMP    AX,0009    ; KEY_PAR = 0
  190. :4C9E 7608       JBE    4CA8 ; no pampering if RE_SULT < 9
  191. :4CA0 836EFA0A   SUB    WORD PTR [BP-06],+0A ; else pamper
  192. :4CA4 835EFC00   SBB    WORD PTR [BP-04],+00 ; and SBB [9548]
  193. :4CA8 C45E0E     LES    BX,[BP+0E] ; reset pointer to E
  194. :4CAB 268B4F02   MOV    CX,ES:[BX+02] ; charge CX [958C]
  195. :4CAF 268B1F     MOV    BX,ES:[BX] ; charge BX slider [958A]
  196. :4CB2 33D2       XOR    DX,DX      ; clear DX to zero
  197. :4CB4 B80A00     MOV    AX,000A    ; 10 in AX
  198. :4CB7 9A930D2720 CALL   2027:0D93  ; call following RO_routine
  199.  
  200.   This is the only routine called from our protection, inside the
  201. loop (therefore 8 times), disassembly from WCB. Examining this
  202. code please remember that we entered here with following
  203. configuration: DX=0, AX=0xA, CX=[958C] and BX=[958A]...
  204.  1.0D93  56      push   si     ; save si
  205.  1.0D94  96      xchg   ax, si ; ax=si, si=0xA
  206.  1.0D95  92      xchg   ax, dx ; dx=0xA ax=dx
  207.  1.0D96  85C0    test   ax, ax ; TEST this zero
  208.  1.0D98  7402    je     0D9C   ; zero only 1st time
  209.  1.0D9A  F7E3    mul    bx     ; BX slider! 0/9/5E/3B2...
  210.  1.0D9C >E305    jcxz   0DA3   ; cx=0? don't multiply!
  211.  1.0D9E  91      xchg   ax, cx ; cx !=0? cx = ax & ax = cx
  212.  1.0D9F  F7E6    mul    si     ;     ax*0xA in ax
  213.  1.0DA1  03C1    add    ax, cx ; ax=  ax*0xA+cx = M_ULT
  214.  1.0DA3 >96      xchg   ax, si ; ax=0xA; si evtl. holds M_ULT
  215.  1.0DA4  F7E3    mul    bx     ; ax= bx*0xA
  216.  1.0DA6  03D6    add    dx, si ; dx= dx_add
  217.  1.0DA8  5E      pop    si     ; restore si
  218.  1.0DA9  CB      retf          ; back to caller with two
  219.                                         parameters: DX and AX
  220. Back_to_main_protection_loop_from_RO_routine:
  221. :4CBC C45E0E     LES    BX,[BP+0E] ; reset pointer
  222. :4CBF 26895702   MOV    ES:[BX+02],DX ; save R_DX par  [958C]
  223. :4CC3 268907     MOV    ES:[BX],AX ; save R_AX par     [958A]
  224. :4CC6 0346FA     ADD    AX,[BP-06] ; add to AX RE_SULT [9546]
  225. :4CC9 1356FC     ADC    DX,[BP-04] ; add to DX KEY_PAR [9548]
  226. :4CCC C45E0E     LES    BX,[BP+0E] ; reset pointer
  227. :4CCF 26895702   MOV    ES:[BX+02],DX ; save R_DX+KEY_PAR [958C]
  228. :4CD3 268907     MOV    ES:[BX],AX ; save R_AX+RE_SULT    [958A]
  229. :4CD6 FF0E8D5E   DEC    WORD PTR [5E8D] ; down_slide SEC_+3
  230. :4CDA 7D05       JGE    4CE1       ; no need to add
  231. :4CDC 83068D5E0A ADD    WORD PTR [5E8D],+0A  ; pamper adding 10
  232. :4CE1 FF068F5E   INC    WORD PTR [5E8F] ; up_slide FIR_+7
  233. :4CE5 A18F5E     MOV    AX,[5E8F]  ; save upslided FIR_+7 in AX
  234. :4CE8 3D0900     CMP    AX,0009    ; is it over 9?
  235. :4CEB 7E05       JLE    4CF2       ; no, go on
  236. :4CED 832E8F5E0A SUB    WORD PTR [5E8F],+0A ; yes, pamper -10
  237. :4CF2 FF0E975E   DEC    WORD PTR [5E97]  ; decrease loop counter
  238. check_loop_counter:
  239. :4CF6 833E975E03 CMP    WORD PTR [5E97],+03  ; counter = 3?
  240. :4CFB 7C03       JL     4D00       ; finish if counter under 3
  241. :4CFD E961FF     JMP    4C61       ; not yet, loop_next_count
  242. loop_is_ended:
  243. :4D00 C45E06     LES    BX,[BP+06] ; reset pointer to input
  244. :4D03 268A4701   MOV    AL,ES:[BX+01] ; load 2nd number (2)
  245. :4D07 98         CBW               ; only low
  246. :4D08 05D0FF     ADD    AX,FFD0    ; clean it
  247. :4D0B BA0A00     MOV    DX,000A    ; DX = 10
  248. :4D0E F7EA       IMUL   DX         ; AX = SEC_*10 = 14
  249. :4D10 C45E06     LES    BX,[BP+06] ; reset pointer
  250. :4D13 50         PUSH   AX         ; save SEC_*10
  251. :4D14 268A07     MOV    AL,ES:[BX] ; load 1st number (1)
  252. :4D17 98         CBW               ; only low
  253. :4D18 8BD0       MOV    DX,AX      ; save in DX
  254. :4D1A 58         POP    AX         ; get SEC_*10
  255. :4D1B 03C2       ADD    AX,DX      ; sum SEC_*10+1st number
  256. :4D1D 05D0FF     ADD    AX,FFD0    ; clean it
  257. :4D20 99         CWD               ; only low
  258. :4D21 C45E0A     LES    BX,[BP+0A] ; get pointer    to   [9582]
  259. :4D24 26895702   MOV    ES:[BX+02],DX ; save 1st (1) in  [9584]
  260. :4D28 268907     MOV    ES:[BX],AX ; save FINAL_SUM (15) [9582]
  261. :4D2B 33D2       XOR    DX,DX      ; DX = 0
  262. :4D2D B80100     MOV    AX,0001    ; FLAG TRUE !
  263. :4D30 E9E6FE     JMP    4C19       ; OK, you_are_a_nice_guy
  264. EXIT:
  265. :4D33 59         POP    CX         ; pop everything and
  266. :4D34 59         POP    CX         ;  return with flag
  267. :4D35 1F         POP    DS         ;  AX=TRUE if RegNum OK
  268. :4D36 5D         POP    BP         ;  with 1st # in     [9584]
  269. :4D37 4D         DEC    BP         ;  with FINAL_SUM in [9582]
  270. :4D38 CB         RETF
  271.  
  272.   Let's translate the preceding code: first of all the pointers:
  273. At line :4B86 we have the first of a long list of stack ptrs:
  274.                         LES BX,[BP+06]
  275.  This stack pointer points to the beginning of the input string,
  276. which, once polished from the "-", has now a length of 10 bytes,
  277. concluded by a 00 fence. At the beginning, before the main loop,
  278. 9 out of our 10 numbers are added, all but the third one.
  279.   Notice that protection has jumped # 3 (and added # 8 out of the
  280. line). The rest is straightforward. Now, at line :4BFD we have
  281. our first "cleaning" instruction. You see: the numbers are
  282. hexadecimal represented by the codes 0x30 to 0x39. If you add
  283. FE50 to the minimum sum you can get adding 9 numbers (0x30*9 =
  284. 0x160) You get 0. The maximum you could have adding 9 numbers,
  285. on the contrary is (0x39*9=0x201), which, added to FE50 gives
  286. 0x51. So we'll have a "magic" number between 0x0 and 0x51 instead
  287. of a number between 0x160 and 0x201. Protection pampers this
  288. result, and retains only the last ciffer: 0-9.  Then protection
  289. divides this number through 0xA, and what happens? DX get's the
  290. REMAINDER of it.
  291.   If we sum the hexcodes of our (1212-1212-12) we get 0x1BE (we
  292. sum only 9 out of then numbers: the third "1" -i.e. "31"- does
  293. not comes into our count); 0x1BE, cleaned and pampered gives E.
  294. Therefore (0xE/0xA = 1) We get 1 with a remainder of 4.
  295.   You may observe that of all possible answers, only sums
  296. finishing with A, B, C, D, E or F give 1 (and rem=0,1,2,3,4 or
  297. 5). Sums finishing 0 1 2 3 4 5 6 7 8 or 9 give 0 as result and
  298. themselves as reminder. The chance of getting a 0,1,2,3 or 4 are
  299. therefore bigger as the chance of getting a 5, 6, 7, 8 or 9. We
  300. are just observing... we do not know yet if this should play a
  301. role or not.
  302.   Now this remainder is compared at :4C11 with the third number
  303. polished from 0x30-0x39 to 0-9. This is the only protection check
  304. for the registration number input: If your third number does not
  305. match with the remainder of the sum of all the 9 others numbers
  306. of your input you are immediately thrown out with FLAG AX=FALSE
  307. (i.e. zero).
  308.  To crack the protection you now have to MODIFY your input string
  309. accordingly. Our new input string will from now on be "1242-1212-
  310. 12": we have changed our third number (originally a "2") to a "4"
  311. to get through this first strainer in the correct way. Only now
  312. protection starts its mathematical part (We do not know yet why
  313. it does it... in order to seed the random product number? To
  314. provide a check for the registration number you'll input at the
  315. end? We'll see).
  316. -    Protection saves the second number of your input (cleaned
  317.      with FFD7) in SEC_+3 [5E8D], pampering it if it is bigger
  318.      than 9 (i.e. if it is 0xA-0xF). Here you'll have therefore
  319.      following correspondence: 0=7 1=8 2=9 3=0 4=1 5=2 6=3 7=4
  320.      8=5 9=6. The second number of your input has got added +3.
  321.      This is value SEC_+3. In (lengthy) C it would look like
  322.      this:
  323.        If (RegString(2)is lower than  7) RegString(2) = RegString(2)+3
  324.        Else Regstring(2) = ((RegString(2)-10)+3)
  325. -    Protection saves your first number in FIR_+7 [5E8F] with a
  326.      different cleaning parameter (FFC9). The next pampering
  327.      adds 0xA if it was not 7/8/9 therefore you have here
  328.      following correspondence 7=0 8=1 9=2 0=3 1=4 2=5 3=6 4=7
  329.      5=8 6=9). This is value FIR_+7. In (lengthy) C it would
  330.      look like this:
  331.        If (RegString(1) is lower than 3) RegString(1) = RegString(1)+7
  332.        Else Regstring(1) = ((RegString(1)-10)+7)
  333.   So protection has "transformed" and stored in [5E8D] and [5E8F]
  334. the two numbers 1 and 2. In our RegString: 1242-1212-12 the first
  335. two numbers "12" are now stored as "94". These will be used as
  336. "slider" parameters inside the main loop, as you will see.
  337.  Only now does protection begin its main loop, starting from the
  338. LAST number, because the counter has been set to 9 (i.e. the
  339. tenth number of RegString). The loop, as you'll see, handles only
  340. the numbers from 10 to 3: it's an 8-times loop that ends without
  341. handling the first and second number. What happens in this
  342. loop?... Well, quite a lot: Protection begins the loop loading
  343. the number (counter+1) from the RegString. Protection then loads
  344. the SEC_+3 down_slider parameter (which began its life as second
  345. number "transformed"), multiplies it with 0xA and then adds the
  346. up_slider parameter FIR_+7 (at the beginning it was the first
  347. number transformed).
  348.      This sum is used as "lookup pointer" to find a parameter
  349. inside a table of parameters in memory, which are all numbers
  350. between 0 and 9. Let's call this value Lkup_val.
  351. Protection looks for data in 1EA7:[Lkup_val]. In our case (we
  352. entered 1242-1212-12, therefore the first SEC_+3 value is 9 and
  353. the first FIR_+7 value is 4): [Lkup_val] = 9*0xA+4; 0x5A+4 =
  354. 0x5E. At line :4C80 therefore AL would load the byte at 1EA7:005E
  355. (let's call it KEY_PAR), which now would be ADDED to the #
  356. counter+1 of this loop. In our case KEY_PAR at 1EA7:005E it's a
  357. "7" and is added to the pampered 0x32=2, giving 9.
  358.      Let's establish first of all which KEY_PAR can possibly get
  359. fetched: the maximum is 0x63 and the minimum is 0x0. The possible
  360. KEY_PARs do therefore dwell in memory between 1EA7: and
  361. 1EA7:0063. Let's have a look at the relative table in memory,
  362. where these KEY_PARs are stored ("our" first 0x5Eth byte is
  363. underlined):
  364. 1EA7:0000 01 03 03 01 09 02 03 00-09 00 04 03 08 07 04 04
  365. 1EA7:0010 05 02 09 00 02 04 01 05-06 06 03 02 00 08 05 06
  366. 1EA7:0020 08 09 05 00 04 06 07 07-02 00 08 00 06 02 04 07
  367. 1EA7:0030 04 04 09 05 09 06 00 06-08 07 00 03 05 09 00 08
  368. 1EA7:0040 03 07 07 06 08 09 01 05-07 04 06 01 04 02 07 01
  369. 1EA7:0050 03 01 08 01 05 03 03 01-02 08 02 01 06 05 07 02
  370. 1EA7:0060 05 09 09 08 02 09 03 00-00 04 05 01 01 03 08 06
  371. 1EA7:0070 01 01 09 00 02 05 05 05-01 07 01 05 08 07 01 09
  372. 1EA7:0080 08 07 07 04 04 08 03 00-06 01 09 08 08 04 09 09
  373. 1EA7:0090 00 07 05 02 03 01 03 08-06 05 07 06 03 07 06 07
  374. 1EA7:00A0 04 02 02 05 02 04 06 02-06 09 09 01 05 02 03 04
  375. 1EA7:00B0 04 00 03 05 00 03 08 07-06 04 08 08 02 00 03 06
  376. 1EA7:00C0 09 00 00 06 09 04 07 02-00 01 01 01 01 00 01 FF
  377. 1EA7:00D0 00 FF FF FF FF 00 FF 01-00 00 00 00 00 00 00 00
  378.  
  379.      An interesting table, where all the correspondences are
  380. between 0 and 9... are we getting some "secret" number here? But,
  381. hey, look there... funny, isn't it? Instead of only 0-0x63 bytes
  382. we have roughly the DOUBLE here: 0-0xC8 bytes (the 01 sequence
  383. starting at CA "feels" like a fence). We'll see later how
  384. important this is. At the moment you should only "perceive" that
  385. something must be going on with a table that's two time what she
  386. should be.
  387.      As I said the result of KEY_PAR + input number is polished
  388. (with a FFDO) and pampered (subtracting, if necessary, 0xA).
  389. Therefore the result will be the (counter+1) input number +
  390. KEY_PAR (let's call it RE_SULT], in our case, (at the beginning
  391. of the loop) a 9. Now (DX=0 because of the CWD instruction) DX
  392. will be saved in [9548] and RE_SULT in [9546].
  393.  Now Protection prepares for the RO_routine: resets its pointer
  394. and charges CX and BX from [958C] and from [958A] respectively,
  395. charges AX with 0xA and sets DX to zero.
  396.  The routine performs various operations on AX and DX and saves
  397. the results in the above mentioned locations [958A] and [958C].
  398.  Now KEY_PAR and RE_SULT are added respectively to the DX and AX
  399. value we got back from the RO_routine call, and saved once more
  400. in the last two locations: AX+RE_SULT in [958A] and DX+KEY_PAR
  401. in [958C]
  402.  Now the value in SEC_+3 is diminished by 1 (if it was 9 it's now
  403. 8, if it was zero it will be pampered to 9). It's a "slider"
  404. parameter (in this case a down_slider), typically used in
  405. relatively complicated protections to give a "random" impression
  406. to the casual observer. The value in FIR_+7, on the contrary, is
  407. augmented by one, from 4 to 5... up_sliding also.
  408.      Protection now handles the next number of your input for the
  409. loop. In our case this loop uses following protection
  410. configuration with our "sliding" parameters:
  411.  Input #  pamp_2nd   pamp_1st   Lookup value  KEY_PAR  # RE_SULT
  412. # 10 = 2, SEC_+3= 9, FIR_+7= 4, Lkup_val = 0x5E, KEY=7 +2 = 9
  413. # 9  = 1, SEC_+3= 8, FIR_+7= 5, Lkup_val = 0x55, KEY=3 +1 = 4
  414. # 8  = 2, SEC_+3= 7, FIR_+7= 6, Lkup_val = 0x4C, KEY=4 +2 = 6
  415. # 7  = 1, SEC_+3= 6, FIR_+7= 7, Lkup_val = 0x43, KEY=7 +1 = 7
  416. # 6  = 2, SEC_+3= 5, FIR_+7= 8, Lkup_val = 0x3A, KEY=0 +2 = 2
  417. # 5  = 1, SEC_+3= 4, FIR_+7= 9, Lkup_val = 0x31, KEY=4 +1 = 5
  418. # 4  = 2, SEC_+3= 3, FIR_+7= 0, Lkup_val = 0x1E, KEY=5 +2 = 7
  419. # 3  = 4, SEC_+3= 2, FIR_+7= 1, Lkup_val = 0x15, KEY=2 +4 = 5
  420. Notice how our "regular" input 21212124 has given an "irregular"
  421. 94672575.
  422.      You may legitimately ask yourself what should all this mean:
  423. what are these RE_SULTs used for? Well they are used to slide
  424. another parameter: this one inside the called routine... this is
  425. what happens to AX and DX inside the routine, and the lines after
  426. the called routine:
  427. :4CBF 26895702   MOV    ES:[BX+02],DX ; save R_DX par  [958C]
  428. :4CC3 268907     MOV    ES:[BX],AX ; save R_AX par     [958A]
  429. :4CC6 0346FA     ADD    AX,[BP-06] ; add to AX RE_SULT [9546]
  430. :4CC9 1356FC     ADC    DX,[BP-04] ; add to DX KEY_PAR [9548]
  431. :4CCC C45E0E     LES    BX,[BP+0E] ; reset pointer to E
  432. :4CCF 26895702   MOV    ES:[BX+02],DX ; save R_DX+KEY_PAR [958C]
  433. :4CD3 268907     MOV    ES:[BX],AX ; save R_AX+RE_SULT    [958A]
  434.  
  435.             :4CC6     :4CC9  :4CCF Odd_DX  :4CD3 slider_sum
  436.   RE_SULT   [958A]    [958C]   [958C]        [958A]
  437.      0         0        0        0            0
  438.      9         5A       0        0            9
  439.      4         3AC      0        0            5E
  440.      6         24F4     0        0            3B2
  441.      7         71CE     1        1            24FB
  442.      2         7220     4        E            71D0
  443.      5         7572     4        90           7225
  444.                                               7579
  445.  
  446. Now the loops ends, having handled the input numbers from tenth
  447. to third. Protection loads the second number and multiplies it
  448. by 10 (let's call this result SEC_*10), in our case 2*0xA=14.
  449. Protection loads the first number and adds it to the
  450. multiplication, in our case 1+0x14=0x15 (FINAL_SUM].
  451. Now everything will be added to FFDO to "clean" it.
  452. Pointer will now be set to the end of the input number.
  453. DX, zeroed by CDW, will be saved as parameter in [9584] and the
  454. cleaned and pampered sum will be saved in [9582].
  455. FLAG is set to true and this routine is finished! No parameter
  456. are passed and the only interesting thing is what actually
  457. happens in the locations [9582], [9584], [958A] and [958C], i.e.:
  458. FINAL_SUM, 0, slider_sum, odd_dx.
  459.      In the next lesson we'll crack everything, but I'll give you
  460. already some hints here, in case you would like to go ahead on
  461. your own: we'll see how the scheme used for the third (the
  462. registration) number show analogies and differences with the
  463. scheme we have studied (and cracked) here for the first number.
  464. Our 3434-3434-3434-3434-34 input string for the registration
  465. number will be transformed in the magic string
  466. 141593384841547431, but this will not work because the "magic"
  467. 12th number: "1" will not correspond to the remainder calculated
  468. inside this check through the previous locations of the other
  469. checks.
  470.      Here the things are more complicated because every little
  471. change in your input string transforms COMPLETELY the "magic"
  472. string... therefore in order to pass the strainer you'll have to
  473. change 3434-3434-3434-3434-34 in (for instance) 7434-3434-3434-
  474. 3434-96. The "magic" string 219702960974498056 that this
  475. registration input gives will go through the protection strainer.
  476. Only then we'll be able to step over and finally crack the whole
  477. protection... it's a pretty complicated one as I said. Now crack
  478. it pupils... you have three months time. From this crack depends
  479. your admission to the Uni, there will be no other admission text
  480. till summer 1997 (it's a hell of work to prepare this crap)...
  481. work well.
  482.  
  483. Well, that's it for this lesson, reader. Not all lessons of my
  484. tutorial are on the Web.
  485.      You 'll obtain the missing lessons IF AND ONLY IF you mail
  486. me back (via anon.penet.fi) some tricks of the trade I may not
  487. know but YOU've discovered. I'll probably know most of them
  488. already, but if they are really new you'll be given full credit,
  489. and even if they are not, should I judge that you "rediscovered"
  490. them with your work, or that you actually did good work on them,
  491. I'll send you the remaining lessons nevertheless. Your
  492. suggestions and critics on the whole crap I wrote are also
  493. welcomed.
  494.  
  495.                                 E-mail +ORC
  496.  
  497.                         +ORC an526164@anon.penet.fi
  498.